Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix a crash when npc tries to heal horse-mounted player #40025

Merged
merged 1 commit into from
Apr 30, 2020

Conversation

Qrox
Copy link
Contributor

@Qrox Qrox commented Apr 30, 2020

Summary

SUMMARY: Bugfixes "Fix a crash when npc tries to heal horse-mounted player."

Purpose of change

Fixes #40001.

game::shared_from assumed that the player cannot be at the same location as a monster, which no longer holds now that mounting creatures is possible. If the player is mounted on a creature g->shared_from( g->u ) returns the mounted creature, so patient in npc::execute_action becomes nullptr after dynamic casting it to player.

Describe the solution

In npc_execute_action, check patient is not null before dereferencing it.

In game::shared_from, check critter is a monster/npc before searching for its shared pointer, and only return the shared pointer if it refers to the same object as critter.

Testing

Loaded the save from #40001 and it no longer crashed. NPCs now also heal the player when they are mounted.

Additional context

Should probably be backported to 0.E.

@ZhilkinSerg ZhilkinSerg added NPC / Factions NPCs, AI, Speech, Factions, Ownership [C++] Changes (can be) made in C++. Previously named `Code` <Bugfix> This is a fix for a bug (or closes open issue) Mechanics: Character / Player Character / Player mechanics labels Apr 30, 2020
src/game.cpp Outdated
Comment on lines 4713 to 4723
if( const shared_ptr_fast<monster> mon_ptr = critter_tracker->find( critter.pos() ) ) {
return std::dynamic_pointer_cast<T>( mon_ptr );
}
if( static_cast<const Creature *>( &critter ) == static_cast<const Creature *>( &u ) ) {
// u is not stored in a shared_ptr, but it won't go out of scope anyway
return std::dynamic_pointer_cast<T>( u_shared_ptr );
}
for( auto &cur_mon : critter_tracker->get_monsters_list() ) {
if( static_cast<const Creature *>( cur_mon.get() ) == static_cast<const Creature *>( &critter ) ) {
return std::dynamic_pointer_cast<T>( cur_mon );
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is a good solution; it makes this function O(n) in the number of monsters, which could have a bad performance impact.

I think it would also work to instead replace the initial if block with:

    if( const shared_ptr_fast<monster> mon_ptr = critter_tracker->find( critter.pos() ) ) {
        if( shared_ptr<T> result = std::dynamic_pointer_cast<T>( mon_ptr ) ) {
            return result;
        }
    }

Then for this case (player riding monster) the cast would fail and the code would fall through to the next check and succeed in returning the player.

@ZhilkinSerg ZhilkinSerg merged commit 5130b68 into CleverRaven:master Apr 30, 2020
@Qrox Qrox deleted the fix-40001 branch May 1, 2020 02:41
@Qrox Qrox mentioned this pull request Jun 15, 2020
kevingranade pushed a commit that referenced this pull request Jun 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
<Bugfix> This is a fix for a bug (or closes open issue) [C++] Changes (can be) made in C++. Previously named `Code` Mechanics: Character / Player Character / Player mechanics NPC / Factions NPCs, AI, Speech, Factions, Ownership
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Game crashes upon returning to my base
3 participants